<!-- 全局文件上传组件 -->
<template>
  <div ref="divRef" class="upload-pic-wrapper">
    <a-upload :accept="accept" :multiple="false" :max-count="1" :before-upload="beforeUpload" :custom-request="customRequest" :show-upload-list="false" class="file-box">
      <div v-if="!picPath" class="picture" :style="picStyle">
        <slot>
          <div class="default-pic">
            <PlusOutlined />
            <div class="upload-text">
              {{ text }}
            </div>
          </div>
        </slot>
      </div>
      <img v-else :src="picPath" :style="picStyle" />
    </a-upload>
  </div>
</template>

<script setup lang="ts">
import { PlusOutlined } from '@ant-design/icons-vue'
import type { UploadProps } from 'ant-design-vue'

interface Props {
  // 文件类型限制
  accept?: string
  // 最大文件大小 (MB)
  maxSize?: number
  // 自定义显示文本
  text?: string
  // 上传接口地址
  uploadUrl?: string
  // 初始文件列表
  value?: string
}

interface Emits {
  (e: 'change', fileVo: FileVo): void
}

const props = withDefaults(defineProps<Props>(), {
  accept: '*',
  maxSize: 10,
  text: '上传图片',
  uploadUrl: '/common/upload',
  value: '',
})

const emit = defineEmits<Emits>()

const divRef = ref<HTMLDivElement>() //

const picPath = ref<string>(props.value) //
const picStyle = ref('') //

onMounted(() => {
  if (divRef.value) {
    const w = divRef.value.offsetWidth
    const h = divRef.value.offsetHeight
    picStyle.value = `width: ${w}px; height: ${h}px;`
  }
})

// 文件上传前的校验
const beforeUpload: UploadProps['beforeUpload'] = file => {
  // 文件大小校验
  const isLtMaxSize = file.size / 1024 / 1024 < props.maxSize
  if (!isLtMaxSize) {
    message.error(`文件大小不能超过 ${props.maxSize}MB`)
    return false
  }

  // 文件类型校验
  if (props.accept !== '*') {
    const acceptTypes = props.accept.split(',').map(type => type.trim())
    const fileType = file.type
    const fileName = file.name
    const fileExt = `.${fileName.split('.').pop()?.toLowerCase()}`

    const isAcceptType = acceptTypes.some(type => {
      if (type.startsWith('.')) {
        return fileExt === type.toLowerCase()
      }
      return fileType.includes(type.replace('*', ''))
    })

    if (!isAcceptType) {
      message.error(`只支持上传 ${props.accept} 格式的文件`)
      return false
    }
  }

  return true
}

// 自定义上传请求
const customRequest: UploadProps['customRequest'] = async options => {
  try {
    // 使用默认上传方法
    const formData = new FormData()
    formData.append('file', options.file as File)
    // 这里可以使用项目的 httpRequest 方法
    const res: FileVo = await httpRequest(props.uploadUrl, formData)
    picPath.value = res.url
    emit('change', res)
  }
  catch (error) {}
}
</script>

<style lang="less" scoped>
.upload-pic-wrapper {
  width: 100%;
  height: 100%;

  .file-box {
    display: inline-block;
    width: 100%;
    height: 100%;

    .picture {
      width: 100%;
      height: 100%;
    }

    .default-pic {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      width: 100%;
      height: 100%;
    }
  }
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }

  100% {
    transform: rotate(360deg);
  }
}
</style>
